package com.elder.common.utils.minio;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.elder.common.core.domain.AjaxResult;
import io.minio.*;
import io.minio.http.Method;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @Author: Greedy
 * @Date: Created in:2022-09-15
 * Description:
 */
@Service
@Slf4j
public class MinioService {

    @Autowired
    private MinioConfig minioConfig;

    @Autowired
    private MinioClient minioClient;

    /**
     * 多上传文件
     * @param
     * @return
     */
    public AjaxResult uploadFile(String fName , MultipartFile[] files) {
        JSONArray result = new JSONArray();
        if (Objects.nonNull(files) && files.length > 0) {
            String bucketName = StrUtil.isNotBlank(minioConfig.getBucketName()) ? minioConfig.getBucketName().replaceAll(",", "") : minioConfig.getBucketName();
            JSONObject object = null;

            String fileName = null;
            for (MultipartFile file : files) {

                try {
                    object = new JSONObject();
                    if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
                        minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
                    }
                    fileName = file.getOriginalFilename();
                    if (StrUtil.isNotBlank(fName)){
                        fileName = fName;
                    }
                    StringBuffer fileNameSB = new StringBuffer();
                    fileNameSB.append(System.currentTimeMillis()).append("_").append(bucketName).append("_");
                    if (StrUtil.isNotBlank(fileName)){
                        fileNameSB.append(fileName.replaceAll(",", ""));
                    }
                    fileName = fileNameSB.toString();
                    PutObjectArgs args = PutObjectArgs.builder()
                            .bucket(bucketName)
                            .object(fileName)
                            .stream(file.getInputStream(), file.getSize(), -1)
                            .contentType(file.getContentType())
                            .build();
                    minioClient.putObject(args);
                    object.put("fileName",fileName);
                    object.put("bucketName",bucketName);
                    object.put("previewUrl",getPreviewUrl(fileName,bucketName));
                    result.add(object);
                    log.info("文件上传成功，文件名称：{}，bucket名称：{}", fileName, bucketName);
                }catch (Exception e){
                    log.error("文件上传失败，文件名称：{}，bucket名称：{}，错误信息：", fileName, bucketName, e);
                }
            }
        }
        return AjaxResult.success(result);
    }

    public JSONObject uploadOneFile(String fName , MultipartFile file) {
        JSONObject object = null;
        if (Objects.nonNull(file)) {
            String bucketName = StrUtil.isNotBlank(minioConfig.getBucketName()) ? minioConfig.getBucketName().replaceAll(",", "") : minioConfig.getBucketName();

            String fileName = null;
            try {
                object = new JSONObject();
                if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
                    minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
                }
                fileName = file.getOriginalFilename();
                if (StrUtil.isNotBlank(fName)){
                    fileName = fName;
                }
                StringBuffer fileNameSB = new StringBuffer();
                fileNameSB.append(System.currentTimeMillis()).append("_").append(bucketName).append("_");
                if (StrUtil.isNotBlank(fileName)){
                    fileNameSB.append(fileName.replaceAll(",", ""));
                }
                fileName = fileNameSB.toString();
                PutObjectArgs args = PutObjectArgs.builder()
                        .bucket(bucketName)
                        .object(fileName)
                        .stream(file.getInputStream(), file.getSize(), -1)
                        .contentType(file.getContentType())
                        .build();
                minioClient.putObject(args);
                object.put("fileName",fileName);
                object.put("bucketName",bucketName);
                object.put("previewUrl",getPreviewUrl(fileName,bucketName));

                log.info("文件上传成功，文件名称：{}，bucket名称：{}", fileName, bucketName);
            }catch (Exception e){
                log.error("文件上传失败，文件名称：{}，bucket名称：{}，错误信息：", fileName, bucketName, e);
            }
        }
        return object;
    }

    /**
     * 获取预览地址
     * @param fileName
     * @return
     */
    public String getPreviewUrl(String fileName,String bucketName) {
        if (StrUtil.isNotBlank(fileName)) {
            bucketName = StrUtil.isNotBlank(bucketName) ? bucketName : minioConfig.getBucketName();
            try {
                minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(fileName).build());
                if (null != minioConfig.getPreviewExpiry()){
                    String presignedObjectUrl = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                            .method(Method.GET).bucket(bucketName).object(fileName)
                            .expiry(minioConfig.getPreviewExpiry(), TimeUnit.HOURS).build());
                    log.info("有时限文件预览地址为：{}，文件名：{}，bucket名：{}，有效时间为：{}", presignedObjectUrl, fileName, bucketName, minioConfig.getPreviewExpiry());
                    return presignedObjectUrl;
                }else {
                    String presignedObjectUrl = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                            .method(Method.GET).bucket(bucketName).object(fileName).build());
                    log.info("文件预览地址为：{}，文件名：{}，bucket名：{}，有效时间为：永久", presignedObjectUrl, fileName, bucketName);
                    int questionMarkIndex = presignedObjectUrl.indexOf("?"); // 查找问号的位置
                    if (questionMarkIndex != -1) {
                        presignedObjectUrl = presignedObjectUrl.substring(0, questionMarkIndex); // 截取问号前面的部分
                    }
                    return presignedObjectUrl;
                }
            } catch (Exception e) {
                log.error("预览文件地址错误，文件名为：{}，bucket名为：{}，错误信息为：", fileName, bucketName, e);
            }
        }
        return null;
    }

    /**
     * 下载文件
     * @param response
     * @param fileName
     * @param bucketName
     */
    public void downloadFile(HttpServletResponse response, String fileName, String bucketName) {
        InputStream inputStream = null;
        if (StrUtil.isNotBlank(fileName)) {
            bucketName = StrUtil.isNotBlank(bucketName) ? bucketName : minioConfig.getBucketName();
            try {
                StatObjectResponse objectStat = minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(fileName).build());
                response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
                response.setContentType(objectStat.contentType());
                response.setCharacterEncoding("UTF-8");
                inputStream = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(fileName).build());
                IOUtils.copy(inputStream, response.getOutputStream());
                log.info("文件下载成功，文件名称：{}，bucket名为：{}", fileName, bucketName);
            } catch (Exception e) {
                log.error("文件下载失败，文件名称：{}，错误信息：", fileName, e);
            } finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        log.error("输入流关闭失败，文件名：{}，错误信息：", fileName, e);
                    }
                }
            }
        }
    }

    /**
     * 删除文件
     * @param fileName
     * @param bucketName
     * @return
     */
    public String delFile(String fileName, String bucketName) {
        if (StrUtil.isNotBlank(fileName)) {
            bucketName = StrUtil.isNotBlank(bucketName) ? bucketName : minioConfig.getBucketName();
            try {
                minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build());
                log.info("文件删除成功，文件名称为：{}，bucket为：{}", fileName, bucketName);
                return "success";
            }catch (Exception e) {
                log.error("删除文件失败，文件名称为：{}，bucket为：{}，错误信息：", bucketName, fileName, e);
                return "删除文件失败，请刷新后重试";
            }
        }
        return "文件不能为空";
    }

    public String delMinioFile(String fileName, String bucketName) {
        if (StrUtil.isNotBlank(fileName)) {
            bucketName = StrUtil.isNotBlank(bucketName) ? bucketName : minioConfig.getBucketName();
            try {
                minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build());
                log.info("文件删除成功，文件名称为：{}，bucket为：{}", fileName, bucketName);
                return "success";
            }catch (Exception e) {
                log.error("删除文件失败，文件名称为：{}，bucket为：{}，错误信息：", bucketName, fileName, e);
                return "删除文件失败，请刷新后重试";
            }
        }
        return "文件不能为空";
    }

    public String delOneFile(String fileName){
        String base_url = "http://47.120.42.179:9000/minio-file/";
        String url = fileName.replace(base_url,"");
        if (StrUtil.isNotBlank(fileName)) {
            String bucketName = minioConfig.getBucketName();
            try {
                minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build());
                log.info("文件删除成功，文件名称为：{}，bucket为：{}", fileName, bucketName);
                return "success";
            }catch (Exception e) {
                log.error("删除文件失败，文件名称为：{}，bucket为：{}，错误信息：", bucketName, fileName, e);
                return "删除文件失败，请刷新后重试";
            }
        }
        return fileName;
    }


}